class Wacther{
    vm:any
    value:any
    cb:any
    oldValue:any
    constructor(vm:any,value:any,cb:any){
        this.vm = vm;
        this.value = value;
        this.cb = cb;
        this.oldValue = this.get();
    }
    //get 获取值触发
    get(){
        Dep.target = this;
        let value = complieUilt.getVal(this.value,this.vm);
        Dep.target = null;
        return value
    }
    //set 设置值是触发
    updata(){
        let newValue = complieUilt.getVal(this.value,this.vm);
        if( newValue != this.oldValue ){
            this.cb(newValue)
        }
    }
}

class Dep{
    watchers:Array<any>;
    static target: this;
    //target(str:string): string
    constructor(){
        this.watchers = [];
        //this.target = aa
    }
    add(watcher:any){
        this.watchers.push(watcher)
    }
    notify(){
        this.watchers.forEach(watcher =>{
            //watcher是一个个的实例观察者
            watcher.updata();
        })
    }
    
}
interface Info{
    el:any,
    data:any,
    this?:any
}
class Vue implements Info{
    el:any;
    data:object;
    constructor(opt:any){
        this.el = opt.el,
        this.data = opt.data,
        new Observer(this.data)//数据劫持
        new Complie(this.el,this)//指令解析
    }
} 
//数据劫持
class Observer implements Info{
    el:any;
    data:any;
    constructor(data:any){
       this.observer(data) 
    }
    observer(data:any){
        if(data && typeof data === 'object'){
            for(let key in data){
                //console.log(data[key])
                this.observerNode(data,key,data[key]);
            }
        }
    }
    observerNode(data:object,key:string,value:any){
        this.observer(value)
        let dep = new Dep();
        Object.defineProperty(data,key,{
            get(){
                Dep.target && dep.add(Dep.target)
                return value;
            },
            set(newValue){
                if(newValue != value){
                    value = newValue
                    dep.notify();
                }
            }
        })
    }
}
//指令解析
class Complie implements Info{
    el:any
    data:any
    vm:any
    constructor(el:any,vm:any){
        this.vm = vm;
        this.el = this.isEmp(el)?el:document.querySelector(el);
        //console.log(document.querySelector(el))
        //console.log(this.vm)
        let fragment = this.fragmentNode(this.el);
        //在内存中解析指令
        this.complie(fragment);
        //编译成功后再放入dom树页面
        this.el.append(fragment)
    }
    
    //把dom节点放入内存中
    fragmentNode(node:any){
        //创建内存节点
        let fragment = document.createDocumentFragment();
        let fitstChild;
        while(fitstChild = node.firstChild){
            fragment.append(fitstChild)
        }
        return fragment
    }
    //判断是否是元素节点
    isEmp(node:any):boolean{
        return node.nodeType === 1;
    }
    //编译指令(一)
    complie(node:any){
        let childNodes = node.childNodes;
        //console.log(childNodes);
        [...childNodes].forEach(item=>{
            if(this.isEmp(item)){
                //就是元素节点
                this.complieEment(item);
                this.complie(item);
            }else{
                //就是文本节点
                this.complieText(item)
            }
        })
    }
    //编译元素节点上的指令
    complieEment(node:any){
        //console.log(node)
        //后去元素上的属性
        let attributes = node.attributes;
        //console.log(attributes);
        [...attributes].forEach(item=>{
            let {name,value} = item
            //console.log(value)
            if(this.isEv(name)){
                let [,model] = name.split('-');
                //console.log(model)
                complieUilt[model](node,value,this.vm)
                //console.log(value,'111111')
            }
        })
    }
    //判断是否以v-开头
    isEv(name:any):boolean{
         return  name.startsWith('v-');
    }
    //编译文本节点里的内容
    complieText(node:any){
        //console.log(node)
        let content = node.textContent;
        //console.log(content)
        if(/\{\{(.+?)\}\}/.test(content)){
            complieUilt.content(node,content,this.vm)
        }
    }
}
//工具类
let complieUilt:any = {
    //获取值
    getVal(value:string,vm:any){
        //console.log(value)
        //[name,username]
        return value.split('.').reduce((prv,next)=>{
            return prv[next]
        },vm.data)
    },
    model(node:any,value:string,vm:any){
        //console.log(node,value,vm)
       let newValue = this.getVal(value,vm);
        //console.log(newValue);
        new Wacther(vm,value,(newValue:string)=>{
            fn(node,newValue);
        })
        let fn = this.Updatar.complieModel;
        fn(node,newValue);
    },
    html(){

    },
    content(node:any,value:any,vm:any){
        console.log(node,value,vm)
        let newValue = value.replace(/\{\{(.+?)\}\}/g,(...ary:any) => {
            new Wacther(vm,ary[1],(newValue:string)=>{
                fn(node,newValue);
            })
           return this.getVal(ary[1],vm)
        })
        console.log(newValue)
        let fn = this.Updatar.complieText;
        fn(node,newValue)
    },
    Updatar:{
        //更新属性节点的value
        complieModel(node:any,newValue:any){
            node.value = newValue
        },
        //更新文本节点里的值
        complieText(node:any,newValue:any){
            node.textContent = newValue
        }
    }
}